package com.iplant.mes.serviceImpl.utils;

import com.iplant.aps.service.po.aps.APSTaskPartPointDay;
import com.iplant.aps.service.po.oms.OMSOrder;
import com.iplant.aps.serviceImpl.dao.oms.OMSOrderDAO;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.ServiceResult;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.cache.CacheUtils;
import com.iplant.base.utils.general.CalendarTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.basic.service.po.mss.MSSMaterial;
import com.iplant.pdm.service.basicenum.pdm.PDMComponentTypes;
import com.iplant.pdm.service.po.fpc.FPCProduct;
import com.iplant.pdm.service.po.fpc.FPCProductCom;
import com.iplant.pdm.service.po.mss.MSSBOMItem;
import com.iplant.pdm.serviceImpl.dao.fpc.FPCProductComDAO;
import com.iplant.pdm.serviceImpl.dao.mss.MSSBOMItemDAO;
import com.iplant.wms.service.basicenum.bill.WMSOutboundOrderStatus;
import com.iplant.wms.service.basicenum.wms.WMSStockRecordType;
import com.iplant.wms.service.po.batch.MSSBatchRange;
import com.iplant.wms.service.po.batch.MSSBatchRecord;
import com.iplant.wms.service.po.bill.WMSOutboundOrder;
import com.iplant.wms.service.po.bill.WMSOutboundOrderItem;
import com.iplant.wms.service.po.mfs.WMSStoreStation;
import com.iplant.wms.service.po.wms.WMSResource;
import com.iplant.wms.service.po.wms.WMSStockRecord;
import com.iplant.wms.serviceImpl.WMSServiceImpl;
import com.iplant.wms.serviceImpl.dao.batch.MSSBatchRangeDAO;
import com.iplant.wms.serviceImpl.dao.batch.MSSBatchRecordDAO;
import com.iplant.wms.serviceImpl.dao.bill.WMSOutboundOrderDAO;
import com.iplant.wms.serviceImpl.dao.bill.WMSOutboundOrderItemDAO;
import com.iplant.wms.serviceImpl.dao.mfs.WMSStoreStationDAO;
import com.iplant.wms.serviceImpl.dao.mrp.MRPDeliveryDAO;
import com.iplant.wms.serviceImpl.dao.wms.WMSResourceDAO;
import com.iplant.wms.serviceImpl.dao.wms.WMSStockRecordDAO;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;


@Slf4j
public class WMSAutoUtils {

    private static WMSAutoUtils Instance = null;

    public static WMSAutoUtils getInstance() {
        if (Instance == null) {
            Instance = new WMSAutoUtils();
        }
        return Instance;
    }

    public WMSAutoUtils() {
    }


    public WMSOutboundOrder CreateOutboundOrder(APSTaskPartPointDay wTaskPartPointDay, OMSOrder wOMSOrder, WMSStockRecordType wStockRecordType) {
        WMSOutboundOrder wOutboundOrder = new WMSOutboundOrder();
        wOutboundOrder.FactoryID = wOMSOrder.FactoryID;
        wOutboundOrder.FactoryCode = wOMSOrder.FactoryCode;
        wOutboundOrder.FactoryName = wOMSOrder.FactoryName;
        wOutboundOrder.TaskDayID = wTaskPartPointDay.ID;
        wOutboundOrder.setType(wStockRecordType.getValue());
        wOutboundOrder.Remark = "Auto";
        wOutboundOrder.Status = WMSOutboundOrderStatus.Saved.getValue();
        return wOutboundOrder;
    }

    public WMSOutboundOrderItem CreateOutboundOrderItem(WMSOutboundOrder wOutboundOrder, OMSOrder wOMSOrder,
                                                        WMSStoreStation wWMSStoreStation, MSSMaterial wMaterial) {
        WMSOutboundOrderItem wOutboundOrderItem = new WMSOutboundOrderItem();
        wOutboundOrderItem.FactoryID = wOutboundOrder.FactoryID;
        wOutboundOrderItem.FactoryCode = wOutboundOrder.FactoryCode;
        wOutboundOrderItem.FactoryName = wOutboundOrder.FactoryName;
        wOutboundOrderItem.OutboundOrderID = wOutboundOrder.ID;
        wOutboundOrderItem.OutboundOrderCode = wOutboundOrder.Code;
        wOutboundOrderItem.OutboundOrderType = wOutboundOrder.Type;
        wOutboundOrderItem.StoreID = wWMSStoreStation.StoreID;
        wOutboundOrderItem.StoreName = wWMSStoreStation.StoreName;
        wOutboundOrderItem.StoreCode = wWMSStoreStation.StoreCode;

        wOutboundOrderItem.DefaultStoreID = wWMSStoreStation.StoreID;
        wOutboundOrderItem.DefaultStoreName = wWMSStoreStation.StoreName;
        wOutboundOrderItem.DefaultStoreCode = wWMSStoreStation.StoreCode;
        wOutboundOrderItem.DefaultStoreStationID = wWMSStoreStation.ID;
        wOutboundOrderItem.DefaultStoreStationName = wWMSStoreStation.Name;
        wOutboundOrderItem.DefaultStoreStationCode = wWMSStoreStation.Code;

        wOutboundOrderItem.StoreRegionID = wWMSStoreStation.StoreRegionID;
        wOutboundOrderItem.StoreRegionName = wWMSStoreStation.StoreRegionName;
        wOutboundOrderItem.StoreRegionCode = wWMSStoreStation.StoreRegionCode;
        wOutboundOrderItem.StoreAreaID = wWMSStoreStation.StoreAreaID;
        wOutboundOrderItem.StoreAreaName = wWMSStoreStation.StoreAreaName;
        wOutboundOrderItem.StoreAreaCode = wWMSStoreStation.StoreAreaCode;
        wOutboundOrderItem.StoreShelfID = wWMSStoreStation.StoreShelfID;
        wOutboundOrderItem.StoreShelfName = wWMSStoreStation.StoreShelfName;
        wOutboundOrderItem.StoreShelfCode = wWMSStoreStation.StoreShelfCode;
        wOutboundOrderItem.StoreStationID = wWMSStoreStation.ID;
        wOutboundOrderItem.StoreStationName = wWMSStoreStation.Name;
        wOutboundOrderItem.StoreStationCode = wWMSStoreStation.Code;
        wOutboundOrderItem.U8_MOCode = wOMSOrder.Code;
        wOutboundOrderItem.ProjectNo = wOMSOrder.Name;
        wOutboundOrderItem.ProjectName = wOMSOrder.Code;
        wOutboundOrderItem.CustomerID = wOMSOrder.CustomerID;
        wOutboundOrderItem.CustomerCode = wOMSOrder.CustomerCode;
        wOutboundOrderItem.CustomerName = wOMSOrder.CustomerName;


        wOutboundOrderItem.MaterialGroupID = wMaterial.MaterialGroupID;
        wOutboundOrderItem.MaterialGroupCode = wMaterial.MaterialGroupCode;
        wOutboundOrderItem.MaterialGroupName = wMaterial.MaterialGroupName;
        wOutboundOrderItem.MaterialFullGroup = wMaterial.MaterialFullGroup;
        wOutboundOrderItem.MaterialID = wMaterial.ID;
        wOutboundOrderItem.MaterialCode = wMaterial.Code;
        wOutboundOrderItem.MaterialName = wMaterial.Name;
        wOutboundOrderItem.UnitID = wMaterial.CYUnitID;
        wOutboundOrderItem.UnitText = wMaterial.CYUnitText;
        wOutboundOrderItem.StockTypeID = 1;

        wOutboundOrderItem.BatchRecordCode = "";

        return wOutboundOrderItem;
    }

    public WMSOutboundOrderItem CreateOutboundOrderItem(WMSOutboundOrder wOutboundOrder, OMSOrder wOMSOrder, WMSStockRecord wmsStockRecord) {
        WMSOutboundOrderItem wOutboundOrderItem = new WMSOutboundOrderItem();
        wOutboundOrderItem.FactoryID = wOutboundOrder.FactoryID;
        wOutboundOrderItem.FactoryCode = wOutboundOrder.FactoryCode;
        wOutboundOrderItem.FactoryName = wOutboundOrder.FactoryName;
        wOutboundOrderItem.OutboundOrderID = wOutboundOrder.ID;
        wOutboundOrderItem.OutboundOrderCode = wOutboundOrder.Code;
        wOutboundOrderItem.OutboundOrderType = wOutboundOrder.Type;
        wOutboundOrderItem.StoreID = wmsStockRecord.StoreID;
        wOutboundOrderItem.StoreName = wmsStockRecord.StoreName;
        wOutboundOrderItem.StoreCode = wmsStockRecord.StoreCode;

        wOutboundOrderItem.DefaultStoreID = wmsStockRecord.StoreID;
        wOutboundOrderItem.DefaultStoreName = wmsStockRecord.StoreName;
        wOutboundOrderItem.DefaultStoreCode = wmsStockRecord.StoreCode;
        wOutboundOrderItem.DefaultStoreStationID = wmsStockRecord.StoreStationID;
        wOutboundOrderItem.DefaultStoreStationName = wmsStockRecord.StoreStationName;
        wOutboundOrderItem.DefaultStoreStationCode = wmsStockRecord.StoreStationCode;

        wOutboundOrderItem.StoreRegionID = wmsStockRecord.StoreRegionID;
        wOutboundOrderItem.StoreRegionName = wmsStockRecord.StoreRegionName;
        wOutboundOrderItem.StoreRegionCode = wmsStockRecord.StoreRegionCode;
        wOutboundOrderItem.StoreAreaID = wmsStockRecord.StoreAreaID;
        wOutboundOrderItem.StoreAreaName = wmsStockRecord.StoreAreaName;
        wOutboundOrderItem.StoreAreaCode = wmsStockRecord.StoreAreaCode;
        wOutboundOrderItem.StoreShelfID = wmsStockRecord.StoreShelfID;
        wOutboundOrderItem.StoreShelfName = wmsStockRecord.StoreShelfName;
        wOutboundOrderItem.StoreShelfCode = wmsStockRecord.StoreShelfCode;
        wOutboundOrderItem.StoreStationID = wmsStockRecord.StoreStationID;
        wOutboundOrderItem.StoreStationName = wmsStockRecord.StoreStationName;
        wOutboundOrderItem.StoreStationCode = wmsStockRecord.StoreStationCode;
        wOutboundOrderItem.U8_MOCode = wmsStockRecord.ProjectNo;
        wOutboundOrderItem.ProjectNo = wmsStockRecord.ProjectNo;
        wOutboundOrderItem.ProjectName = wmsStockRecord.ProjectNo;
        wOutboundOrderItem.StoreID = wOMSOrder.ID;
        wOutboundOrderItem.CustomerID = wOMSOrder.CustomerID;
        wOutboundOrderItem.CustomerCode = wOMSOrder.CustomerCode;
        wOutboundOrderItem.CustomerName = wOMSOrder.CustomerName;

        wOutboundOrderItem.MaterialGroupID = wmsStockRecord.MaterialGroupID;
        wOutboundOrderItem.MaterialGroupCode = wmsStockRecord.MaterialGroupCode;
        wOutboundOrderItem.MaterialGroupName = wmsStockRecord.MaterialGroupName;
        wOutboundOrderItem.MaterialFullGroup = wmsStockRecord.MaterialFullGroup;
        wOutboundOrderItem.MaterialID = wmsStockRecord.MaterialID;
        wOutboundOrderItem.MaterialCode = wmsStockRecord.MaterialCode;
        wOutboundOrderItem.MaterialName = wmsStockRecord.MaterialName;
        wOutboundOrderItem.UnitID = wmsStockRecord.UnitID;
        wOutboundOrderItem.UnitText = wmsStockRecord.UnitText;
        wOutboundOrderItem.StockTypeID = wmsStockRecord.StockTypeID;

        wOutboundOrderItem.BatchRecordCode = wmsStockRecord.BatchRecordCode;
        wOutboundOrderItem.BatchRecordID = wmsStockRecord.BatchRecordID;
        wOutboundOrderItem.StockRecordID = wmsStockRecord.ID;

        return wOutboundOrderItem;
    }

    /**
     * 自动原材料扣减
     *
     * @param wLoginUser
     * @param wTaskPartPointDay
     * @param wNumber
     */
    public void WMS_AutoOutStock(BMSEmployee wLoginUser, APSTaskPartPointDay wTaskPartPointDay, Map<Integer, String> wMaterialBatchNoMap,
                                 int wStationID, float wNumber, OutResult<Integer> wErrorCode) {
        try {
            //考虑入库时按批次入库，出库按批次出库
            //一个班次日计划只有一个出库单
            //查询本班次出库单
            if (wTaskPartPointDay == null || wTaskPartPointDay.ID <= 0)
                return;

            if (!wTaskPartPointDay.StationID.contains(wStationID)) {
                wErrorCode.Result = ExceptionTypes.NotFound.getValue();
                return;
            }

            OMSOrder wOMSOrder = OMSOrderDAO.getInstance().SelectPO(wLoginUser, wTaskPartPointDay.OrderID, "", wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wOMSOrder == null || wOMSOrder.ID <= 0) {
                wErrorCode.Result = ExceptionTypes.NotFound.getValue();
                return;
            }

            //获取对应工序的BOM清单
            List<MSSBOMItem> wMSSBOMItemList = MSSBOMItemDAO.getInstance().MSS_SelectBOMItemByRouteID(wLoginUser, -1,
                    wTaskPartPointDay.RoutePartID, wTaskPartPointDay.RoutePartPointID, Pagination.getMaxSize(MSSBOMItem.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;
            if (wMSSBOMItemList == null || wMSSBOMItemList.size() == 0)
                return;
            //查询工位库位对应表
            List<WMSResource> wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                    -1, -1, -1, -1, StringUtils.parseListArgs(wStationID),
                    null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;
            if (wResourceList == null)
                wResourceList = new ArrayList<>();

            List<Integer> wStoreStationIDs = wResourceList.stream().map(p -> p.StoreStationID).distinct().collect(Collectors.toList());

            wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                    -1, -1, -1, -1, wTaskPartPointDay.StationID,
                    null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;
            if (wResourceList == null || wResourceList.size() == 0) {
                wErrorCode.Result = ExceptionTypes.NotFound.getValue();
                return;
            }
            List<Integer> wStoreStationIDList = wResourceList.stream().map(p -> p.StoreStationID).distinct().collect(Collectors.toList());


            List<Integer> wMaterialIDList = wMSSBOMItemList.stream().map(p -> p.MaterialID).distinct().collect(Collectors.toList());
            wMaterialIDList.removeIf(p -> p <= 0);

            if (wMaterialIDList.size() == 0)
                return;
            //查询库位库存信息
            List<WMSStockRecord> wStockRecordList = WMSStockRecordDAO.getInstance().WMS_QueryStockRecordList(wLoginUser,
                    -1, -1, wMaterialIDList, Pagination.getMaxSize(WMSStockRecord.class), wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wStockRecordList == null || wStockRecordList.size() == 0)
                return;

            Map<Integer, List<WMSStockRecord>> wStockRecordListMap
                    = wStockRecordList.stream().collect(Collectors.groupingBy(p -> p.MaterialID));

            WMSOutboundOrder wWMSOutboundOrder = WMSOutboundOrderDAO.getInstance()
                    .WMS_SelectOutboundOrderByTaskID(wLoginUser, wTaskPartPointDay.ID,
                            WMSStockRecordType.ProductionOutOfStock.getValue(), wErrorCode);
            if (wErrorCode.Result != 0)
                return;
            if (wWMSOutboundOrder == null || wWMSOutboundOrder.ID <= 0) {
                wWMSOutboundOrder = this.CreateOutboundOrder(wTaskPartPointDay, wOMSOrder, WMSStockRecordType.ProductionOutOfStock);
                wWMSOutboundOrder.Status = WMSOutboundOrderStatus.OutOfStock.getValue();
                WMSOutboundOrderDAO.getInstance().UpdatePo(wLoginUser, wWMSOutboundOrder, wErrorCode);
                if (wErrorCode.Result != 0)
                    return;
            } else if (wWMSOutboundOrder.ItemList == null || wWMSOutboundOrder.ItemList.size() == 0) {
                wWMSOutboundOrder.ItemList = WMSOutboundOrderItemDAO.getInstance().WMS_SelectOutboundOrderItemList(wLoginUser,
                        wWMSOutboundOrder.ID, Pagination.getMaxSize(WMSOutboundOrderItem.class), wErrorCode);
                if (wErrorCode.Result != 0)
                    return;
            }
            Map<Integer, Map<Integer, WMSOutboundOrderItem>> wOutboundOrderItemMaterialMap;
            if (wWMSOutboundOrder.ItemList == null) {
                wWMSOutboundOrder.ItemList = new ArrayList<>();
                wOutboundOrderItemMaterialMap = new HashMap<>();
            } else {
                wOutboundOrderItemMaterialMap = wWMSOutboundOrder.ItemList.stream().collect(Collectors.groupingBy(p -> p.MaterialID,
                        Collectors.toMap(q -> q.StockRecordID, q -> q, (o1, o2) -> o1)));
            }

            //创建子项  若出库单无此子项，则创建，有则增加对应

            double wNeedFQTY = 1;
            List<WMSStockRecord> wStockRecordListTemp;

            WMSOutboundOrderItem wmsOutboundOrderItem;

            List<WMSOutboundOrderItem> wOutboundOrderItemList = new ArrayList<>();

            for (MSSBOMItem mssbomItem : wMSSBOMItemList) {
                if (!wStockRecordListMap.containsKey(mssbomItem.MaterialID))
                    continue;

                wNeedFQTY = mssbomItem.MaterialNumber * wNumber;

                wStockRecordList = wStockRecordListMap.get(mssbomItem.MaterialID);

                if (!wOutboundOrderItemMaterialMap.containsKey(mssbomItem.MaterialID))
                    wOutboundOrderItemMaterialMap.put(mssbomItem.MaterialID, new HashMap<>());
                String wBatchNo;
                if (wMaterialBatchNoMap.containsKey(mssbomItem.MaterialID)) {
                    wBatchNo = wMaterialBatchNoMap.get(mssbomItem.MaterialID);
                } else {
                    wBatchNo = "";
                }

                //region step 1 存在同批次库存直接扣除   库存时间较长的优先

                List<Integer> wStockRecordIDList = wOutboundOrderItemMaterialMap.get(mssbomItem.MaterialID).keySet().stream().collect(Collectors.toList());
                wStockRecordListTemp = wStockRecordList.stream().filter(p -> wStockRecordIDList.contains(p.ID) &&
                                (StringUtils.isEmpty(wBatchNo) || p.BatchRecordCode.equalsIgnoreCase(wBatchNo)))
                        .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

                for (WMSStockRecord wmsStockRecord : wStockRecordListTemp) {

                    if (!wOutboundOrderItemMaterialMap.get(mssbomItem.MaterialID).containsKey(wmsStockRecord.ID))
                        continue;

                    wmsOutboundOrderItem = wOutboundOrderItemMaterialMap.get(mssbomItem.MaterialID).get(wmsStockRecord.ID);


                    if (wmsStockRecord.MaterialMarginNum > wNeedFQTY) {

                        wmsOutboundOrderItem.FQTY += wNeedFQTY;
                        wmsOutboundOrderItem.OutboundQuantity += wNeedFQTY;
                        wmsStockRecord.MaterialMarginNum -= wNeedFQTY;
                        wNeedFQTY = 0;
                    } else {
                        wmsOutboundOrderItem.FQTY += wmsStockRecord.MaterialMarginNum;
                        wmsOutboundOrderItem.OutboundQuantity += wmsStockRecord.MaterialMarginNum;
                        wmsStockRecord.MaterialMarginNum = 0;
                        wNeedFQTY -= wmsStockRecord.MaterialMarginNum;
                    }
                    //直接修改明细单
                    wOutboundOrderItemList.add(wmsOutboundOrderItem);

                    if (wNeedFQTY <= 0) {
                        break;
                    }
                }
                if (wNeedFQTY <= 0)
                    continue;

                //endregion


                //region step 1.1 批次号相同  同库位库存  扣除已经扣过 且库存时间较长的
                wStockRecordListTemp = wStockRecordList.stream().filter(p -> wStoreStationIDs.contains(p.StoreStationID) &&
                                (StringUtils.isEmpty(wBatchNo) || p.BatchRecordCode.equalsIgnoreCase(wBatchNo)))
                        .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

                wNeedFQTY = this.AddOutboundOrderItem(wStockRecordListTemp, wWMSOutboundOrder, wOMSOrder, wNeedFQTY, wOutboundOrderItemList);

                if (wNeedFQTY <= 0)
                    continue;

                //endregion

                //region step 1.2 批次号相同  同工序不同工位库位库存   扣除已经扣过 且库存时间较长的

                wStockRecordListTemp = wStockRecordList.stream().filter(p -> wStoreStationIDList.contains(p.StoreStationID) &&
                                (StringUtils.isEmpty(wBatchNo) || p.BatchRecordCode.equalsIgnoreCase(wBatchNo)))
                        .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

                wNeedFQTY = this.AddOutboundOrderItem(wStockRecordListTemp, wWMSOutboundOrder, wOMSOrder, wNeedFQTY, wOutboundOrderItemList);
                if (wNeedFQTY <= 0)
                    continue;

                //endregion

                //region step 1.3 批次号相同  不同工序库位库存   扣除已经扣过 且库存时间较长的

                wStockRecordListTemp = wStockRecordList.stream().filter(p -> !wStoreStationIDList.contains(p.StoreStationID) &&
                                (StringUtils.isEmpty(wBatchNo) || p.BatchRecordCode.equalsIgnoreCase(wBatchNo)))
                        .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

                wNeedFQTY = this.AddOutboundOrderItem(wStockRecordListTemp, wWMSOutboundOrder, wOMSOrder, wNeedFQTY, wOutboundOrderItemList);
                if (wNeedFQTY <= 0)
                    continue;

                //endregion

                //region step 2 同工位库位 不同批次号   扣除已经扣过 且库存时间较长的

                wStockRecordListTemp = wStockRecordList.stream().filter(p -> wStoreStationIDs.contains(p.StoreStationID) &&
                                (StringUtils.isEmpty(wBatchNo) || !p.BatchRecordCode.equalsIgnoreCase(wBatchNo)))
                        .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

                wNeedFQTY = this.AddOutboundOrderItem(wStockRecordListTemp, wWMSOutboundOrder, wOMSOrder, wNeedFQTY, wOutboundOrderItemList);
                if (wNeedFQTY <= 0)
                    continue;
                //endregion

                //region step 2.1 同工序库位 不同批次号   扣除已经扣过 且库存时间较长的

                wStockRecordListTemp = wStockRecordList.stream().filter(p -> wStoreStationIDList.contains(p.StoreStationID) &&
                                (StringUtils.isEmpty(wBatchNo) || !p.BatchRecordCode.equalsIgnoreCase(wBatchNo)))
                        .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

                wNeedFQTY = this.AddOutboundOrderItem(wStockRecordListTemp, wWMSOutboundOrder, wOMSOrder, wNeedFQTY, wOutboundOrderItemList);
                if (wNeedFQTY <= 0)
                    continue;
                //endregion

                //region step 3  不同工序库位 不同批次号  扣除已经扣过 且库存时间较长的

                wStockRecordListTemp = wStockRecordList.stream().filter(p -> !wStoreStationIDList.contains(p.StoreStationID) &&
                                (StringUtils.isEmpty(wBatchNo) || !p.BatchRecordCode.equalsIgnoreCase(wBatchNo)))
                        .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

                wNeedFQTY = this.AddOutboundOrderItem(wStockRecordListTemp, wWMSOutboundOrder, wOMSOrder, wNeedFQTY, wOutboundOrderItemList);
                if (wNeedFQTY <= 0)
                    continue;
                //endregion

                if (wNeedFQTY > 0) {
                    //库存最多扣减为0    但是需要备注无库存可扣减说明   暂时使用日志解决
                    log.info("原料{0} {1}在{2}工序出库库存不足", mssbomItem.MaterialNo, mssbomItem.MaterialName, wTaskPartPointDay.RoutePartPointName);

                }

            }

            ServiceResult<Integer> wServiceResult = WMSServiceImpl.getInstance().WMS_UpdateOutboundOrderItemList(wLoginUser, wOutboundOrderItemList);

            if (StringUtils.isNotEmpty(wServiceResult.FaultCode)) {
                log.info("WMS_AutoOutStock WMS_UpdateOutboundOrderItemList {}", wServiceResult.FaultCode);
            }

        } catch (Exception e) {
            wErrorCode.Result = ExceptionTypes.Exception.getValue();
            log.error("WMS_AutoOutStock", e);
        }
    }

    private double AddOutboundOrderItem(List<WMSStockRecord> wStockRecordListTemp, WMSOutboundOrder wWMSOutboundOrder, OMSOrder wOMSOrder, double wNeedFQTY, List<WMSOutboundOrderItem> wOutboundOrderItemList) {


        WMSOutboundOrderItem wmsOutboundOrderItem;

        for (WMSStockRecord wmsStockRecord : wStockRecordListTemp) {

            if (wmsStockRecord.MaterialMarginNum <= 0)
                continue;

            wmsOutboundOrderItem = this.CreateOutboundOrderItem(wWMSOutboundOrder, wOMSOrder, wmsStockRecord);

            if (wmsStockRecord.MaterialMarginNum > wNeedFQTY) {

                wmsOutboundOrderItem.FQTY += wNeedFQTY;
                wmsOutboundOrderItem.OutboundQuantity += wNeedFQTY;
                wmsStockRecord.MaterialMarginNum -= wNeedFQTY;
                wNeedFQTY = 0;
            } else {
                wmsOutboundOrderItem.FQTY += wmsStockRecord.MaterialMarginNum;
                wmsOutboundOrderItem.OutboundQuantity += wmsStockRecord.MaterialMarginNum;
                wmsStockRecord.MaterialMarginNum = 0;
                wNeedFQTY -= wmsStockRecord.MaterialMarginNum;
            }
            //直接修改明细单
            wOutboundOrderItemList.add(wmsOutboundOrderItem);

            if (wNeedFQTY <= 0) {
                break;
            }
        }

        return wNeedFQTY;
    }


    /**
     * 自动成品入库
     *
     * @param wLoginUser
     * @param wTaskPartPointDay
     * @param wWorkPieceNoList  出厂编码列表
     */
    public void WMS_AutoInStock(BMSEmployee wLoginUser, APSTaskPartPointDay wTaskPartPointDay, int wStationID, List<String> wWorkPieceNoList, OutResult<Integer> wErrorCode) {

        //一个班次日计划只有一个入库单
        try {

            if (wTaskPartPointDay == null || wTaskPartPointDay.ID <= 0)
                return;

            OMSOrder wOMSOrder = OMSOrderDAO.getInstance().SelectPO(wLoginUser, wTaskPartPointDay.OrderID, "", wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wOMSOrder == null || wOMSOrder.ID <= 0)
                return;

            FPCProduct wFPCProduct = CacheUtils.GetCacheInfo(FPCProduct.class, wTaskPartPointDay.ProductID, "");
            if (wFPCProduct == null || wFPCProduct.ID <= 0)
                return;
            if (wFPCProduct.MaterialID <= 0) {
                log.info("产品:{0} {1} 未配置物料号", wFPCProduct.Code, wFPCProduct.Name);
                return;
            }
            MSSMaterial wMaterial = CacheUtils.GetCacheInfo(MSSMaterial.class, wFPCProduct.MaterialID, "");
            if (wMaterial == null || wMaterial.ID <= 0) {
                log.info("产品:{0} {1} 配置的物料ID{2}不存在", wFPCProduct.Code, wFPCProduct.Name, wFPCProduct.MaterialID);
                return;
            }

            this.WMS_AutoInStock(wLoginUser, wTaskPartPointDay, wOMSOrder, wMaterial, wStationID, wWorkPieceNoList, wErrorCode);

        } catch (Exception e) {
            wErrorCode.Result = ExceptionTypes.Exception.getValue();
            log.error("WMS_AutoInStock", e);
        }
    }


    /**
     * 半成品出库
     * 交接扣减半成品库存
     *
     * @param wLoginUser
     * @param wTaskPartPointDay
     * @param wWorkPieceNoList  原材料扫码数据
     */
    public void WMS_AutoSemiOutStock(BMSEmployee wLoginUser, APSTaskPartPointDay wTaskPartPointDay,
                                     List<String> wWorkPieceNoList, int wStationID, OutResult<Integer> wErrorCode) {
        //一个班次日计划只有一个入库单
        try {

            if (wTaskPartPointDay == null || wTaskPartPointDay.ID <= 0)
                return;

            OMSOrder wOMSOrder = OMSOrderDAO.getInstance().SelectPO(wLoginUser, wTaskPartPointDay.OrderID, "", wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wOMSOrder == null || wOMSOrder.ID <= 0 || wTaskPartPointDay.ProductID <= 0)
                return;
            /**
             * 原材料类型的出库（原材料扫码数据）
             */
            FPCProductCom wFPCProductCom = FPCProductComDAO.getInstance().FPC_SelectProductCom(wLoginUser, wTaskPartPointDay.ProductID, wTaskPartPointDay.ScanComponentType, wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wFPCProductCom == null || wFPCProductCom.ID <= 0 || wFPCProductCom.MaterialID <= 0) {
                log.info("产品:{0} 元件{1} 未配置物料号", wTaskPartPointDay.ProductNo, PDMComponentTypes.getEnumType(wTaskPartPointDay.ScanComponentType).getLabel());
                return;
            }

            MSSMaterial wMaterial = CacheUtils.GetCacheInfo(MSSMaterial.class, wFPCProductCom.MaterialID, "");
            if (wMaterial == null || wMaterial.ID <= 0) {
                log.info("产品:{0} 配置的物料ID{1}不存在", wTaskPartPointDay.ProductNo, wFPCProductCom.MaterialID);
                return;
            }

            //查询工位库位对应表
            List<WMSResource> wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                    -1, -1, -1, -1, StringUtils.parseListArgs(wStationID),
                    null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;
            if (wResourceList == null || wResourceList.size() == 0) {
                wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                        -1, -1, -1, -1, wTaskPartPointDay.StationID,
                        null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
                if (wErrorCode.Result != 0)
                    return;
                if (wResourceList == null || wResourceList.size() == 0) {
                    wErrorCode.Result = ExceptionTypes.NotFound.getValue();
                    return;
                }
            }
            List<Integer> wStoreStationIDList = wResourceList.stream().map(p -> p.StoreStationID).distinct().collect(Collectors.toList());

            //查询库位库存信息
            List<WMSStockRecord> wStockRecordList = WMSStockRecordDAO.getInstance().WMS_QueryStockRecordList(wLoginUser,
                    -1, wStoreStationIDList, wMaterial.ID, Pagination.getMaxSize(WMSStockRecord.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;

            if (wStockRecordList == null || wStockRecordList.size() == 0) {
                log.info("产品:{0} 元件{1} 物料{2} 无库存", wTaskPartPointDay.ProductNo,
                        PDMComponentTypes.getEnumType(wTaskPartPointDay.ScanComponentType).getLabel(), wMaterial.Code);
                return;
            }
            Map<String, WMSStockRecord> wStockRecordMap = wStockRecordList.stream().collect(Collectors.toMap(p -> p.Code, p -> p, (o1, o2) -> o1));


            WMSOutboundOrder wWMSOutboundOrder = WMSOutboundOrderDAO.getInstance()
                    .WMS_SelectOutboundOrderByTaskID(wLoginUser, wTaskPartPointDay.ID,
                            WMSStockRecordType.ProductionWarehousing.getValue(), wErrorCode);

            if (wWMSOutboundOrder == null || wWMSOutboundOrder.ID <= 0) {
                wWMSOutboundOrder = this.CreateOutboundOrder(wTaskPartPointDay, wOMSOrder, WMSStockRecordType.ProductionWarehousing);

                WMSOutboundOrderDAO.getInstance().UpdatePo(wLoginUser, wWMSOutboundOrder, wErrorCode);
                if (wErrorCode.Result != 0)
                    return;
            } else if (wWMSOutboundOrder.ItemList == null || wWMSOutboundOrder.ItemList.size() == 0) {
                wWMSOutboundOrder.ItemList = WMSOutboundOrderItemDAO.getInstance().WMS_SelectOutboundOrderItemList(wLoginUser,
                        wWMSOutboundOrder.ID, Pagination.getMaxSize(WMSOutboundOrderItem.class), wErrorCode);
                if (wErrorCode.Result != 0)
                    return;

                if (wWMSOutboundOrder.ItemList == null)
                    wWMSOutboundOrder.ItemList = new ArrayList<>();
            }

            Map<String, List<WMSOutboundOrderItem>> wOutboundOrderItemMap = wWMSOutboundOrder.ItemList.stream()
                    .collect(Collectors.groupingBy(p -> p.BatchRecordCode));
            if (wErrorCode.Result != 0)
                return;


            WMSOutboundOrderItem wItem;
            List<WMSOutboundOrderItem> wWMSOutboundOrderItemList = new ArrayList<>();
            for (String wWorkPieceNo : wWorkPieceNoList) {
                if (wOutboundOrderItemMap.containsKey(wWorkPieceNo))
                    continue;

                if (!wStockRecordMap.containsKey(wWorkPieceNo))
                    continue;

                wItem = this.CreateOutboundOrderItem(wWMSOutboundOrder, wOMSOrder, wStockRecordMap.get(wWorkPieceNo));

                wItem.FQTY = 1;
                wItem.OutboundQuantity = 1;

                wOutboundOrderItemMap.put(wWorkPieceNo, StringUtils.parseListArgs(wItem));
                wWMSOutboundOrder.ItemList.add(wItem);
                wWMSOutboundOrderItemList.add(wItem);
            }

            ServiceResult<Integer> wServiceResult = WMSServiceImpl.getInstance().WMS_UpdateOutboundOrderItemList(wLoginUser, wWMSOutboundOrderItemList);

            if (StringUtils.isNotEmpty(wServiceResult.FaultCode)) {
                log.info("WMS_AutoSemiOutStock WMS_UpdateOutboundOrderItemList {}", wServiceResult.FaultCode);
            }


            MRPDeliveryDAO.getInstance().MRP_UpdateDeliveryFQTYUsed(wLoginUser,  wTaskPartPointDay.StationDate,
                    CalendarTool.AddCalendar( wTaskPartPointDay.StationDate,Calendar.DAY_OF_MONTH,1), wErrorCode);

        } catch (Exception e) {
            wErrorCode.Result = ExceptionTypes.Exception.getValue();
            log.error("WMS_AutoSemiOutStock", e);
        }


    }

    /**
     * 半成品入库
     * 交接 下工序增加半成品库存
     *
     * @param wLoginUser
     * @param wTaskPartPointDay 接收物料的工序任务
     */
    public void WMS_AutoSemiInStock(BMSEmployee wLoginUser, APSTaskPartPointDay wTaskPartPointDay, int wStationID, List<String> wWorkPieceNoList, OutResult<Integer> wErrorCode) {
        //一个班次日计划只有一个入库单
        try {

            if (wTaskPartPointDay == null || wTaskPartPointDay.ID <= 0)
                return;

            OMSOrder wOMSOrder = OMSOrderDAO.getInstance().SelectPO(wLoginUser, wTaskPartPointDay.OrderID, "", wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wOMSOrder == null || wOMSOrder.ID <= 0)
                return;

            /**
             * 半成品的入库（半成品扫码数据）
             */
            FPCProductCom wFPCProductCom = FPCProductComDAO.getInstance().FPC_SelectProductCom(wLoginUser,
                    wTaskPartPointDay.ProductID, wTaskPartPointDay.ScanComponentType, wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wFPCProductCom == null || wFPCProductCom.ID <= 0 || wFPCProductCom.MaterialID <= 0) {
                log.info("产品:{0} 元件{1} 未配置物料号", wTaskPartPointDay.ProductNo, PDMComponentTypes.getEnumType(wTaskPartPointDay.ScanComponentType).getLabel());
                return;
            }

            MSSMaterial wMaterial = CacheUtils.GetCacheInfo(MSSMaterial.class, wFPCProductCom.MaterialID, "");
            if (wMaterial == null || wMaterial.ID <= 0) {
                log.info("产品:{0} 配置的物料ID{1}不存在", wTaskPartPointDay.ProductNo, wFPCProductCom.MaterialID);
                return;
            }

            this.WMS_AutoInStock(wLoginUser, wTaskPartPointDay, wOMSOrder, wMaterial, wStationID, wWorkPieceNoList, wErrorCode);

        } catch (Exception e) {
            wErrorCode.Result = ExceptionTypes.Exception.getValue();
            log.error("WMS_AutoSemiInStock", e);
        }

    }


    private void WMS_AutoInStock(BMSEmployee wLoginUser, APSTaskPartPointDay wTaskPartPointDay,
                                 OMSOrder wOMSOrder ,  MSSMaterial wMaterial, int wStationID, List<String> wWorkPieceNoList, OutResult<Integer> wErrorCode) {
        //一个班次日计划只有一个入库单


        List<MSSBatchRecord> wBatchRecordList = MSSBatchRecordDAO.getInstance().MSS_SelectBatchRecordList(wLoginUser, wWorkPieceNoList,
                wMaterial.ID, Pagination.getMaxSize(MSSBatchRecord.class), wErrorCode);

        if (wErrorCode.Result != 0)
            return;

        Map<String, MSSBatchRecord> wBatchRecordMap = wBatchRecordList.stream().collect(Collectors.toMap(p -> p.Code, p -> p, (o1, o2) -> o1));

        MSSBatchRange wMSSBatchRange = MSSBatchRangeDAO.getInstance().MSS_QueryBatchRange(wLoginUser, wOMSOrder.CustomerID, wMaterial.Code, wErrorCode);

        if (wErrorCode.Result != 0)
            return;


        //查询工位库位对应表
        List<WMSResource> wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                -1, -1, -1, -1, StringUtils.parseListArgs(wStationID),
                null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
        if (wErrorCode.Result != 0)
            return;
        if (wResourceList == null || wResourceList.size() == 0) {
            wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                    -1, -1, -1, -1, wTaskPartPointDay.StationID,
                    null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;
            if (wResourceList == null || wResourceList.size() == 0) {
                wErrorCode.Result = ExceptionTypes.NotFound.getValue();
                return;
            }
        }
        List<Integer> wStoreStationIDList = wResourceList.stream().map(p -> p.StoreStationID).distinct().collect(Collectors.toList());

        List<WMSStoreStation> wStoreStationList = WMSStoreStationDAO.getInstance().SelectPOList(wLoginUser, wStoreStationIDList,
                Pagination.getMaxSize(WMSStoreStation.class), wErrorCode);

        if (wErrorCode.Result != 0)
            return;

        if (wStoreStationList == null || wStoreStationList.size() == 0) {
            wErrorCode.Result = ExceptionTypes.NotFound.getValue();
            return;
        }

        WMSOutboundOrder wWMSOutboundOrder = WMSOutboundOrderDAO.getInstance()
                .WMS_SelectOutboundOrderByTaskID(wLoginUser, wTaskPartPointDay.ID,
                        WMSStockRecordType.ProductionWarehousing.getValue(), wErrorCode);

        if (wWMSOutboundOrder == null || wWMSOutboundOrder.ID <= 0) {
            wWMSOutboundOrder = this.CreateOutboundOrder(wTaskPartPointDay, wOMSOrder, WMSStockRecordType.ProductionWarehousing);

            WMSOutboundOrderDAO.getInstance().UpdatePo(wLoginUser, wWMSOutboundOrder, wErrorCode);
            if (wErrorCode.Result != 0)
                return;
        } else if (wWMSOutboundOrder.ItemList == null || wWMSOutboundOrder.ItemList.size() == 0) {
            wWMSOutboundOrder.ItemList = WMSOutboundOrderItemDAO.getInstance().WMS_SelectOutboundOrderItemList(wLoginUser,
                    wWMSOutboundOrder.ID, Pagination.getMaxSize(WMSOutboundOrderItem.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;

            if (wWMSOutboundOrder.ItemList == null)
                wWMSOutboundOrder.ItemList = new ArrayList<>();
        }

        Map<String, List<WMSOutboundOrderItem>> wOutboundOrderItemMap = wWMSOutboundOrder.ItemList.stream()
                .collect(Collectors.groupingBy(p -> p.BatchRecordCode));


        //
        WMSOutboundOrderItem wItem;
        List<WMSOutboundOrderItem> wWMSOutboundOrderItemList = new ArrayList<>();
        for (String wWorkPieceNo : wWorkPieceNoList) {
            if (wOutboundOrderItemMap.containsKey(wWorkPieceNo))
                continue;


            wItem = this.CreateOutboundOrderItem(wWMSOutboundOrder, wOMSOrder, wStoreStationList.get(0), wMaterial);

            if (!wBatchRecordMap.containsKey(wWorkPieceNo)) {
                MSSBatchRecord wBatchRecord = new MSSBatchRecord();
                wBatchRecord.ID = wItem.BatchRecordID;
                wBatchRecord.Code = wWorkPieceNo;
                wBatchRecord.ExpireDate = CalendarTool.AddCalendar(wBatchRecord.ExpireDate, Calendar.YEAR, 1);

                wBatchRecord.FactoryID = wItem.FactoryID;
                wBatchRecord.FactoryCode = wItem.FactoryCode;
                wBatchRecord.FactoryName = wItem.FactoryName;
                wBatchRecord.CustomerID = wItem.SupplierID;
                wBatchRecord.CustomerCode = wItem.SupplierCode;
                wBatchRecord.CustomerName = wItem.SupplierName;

                wBatchRecord.MaterialID = wItem.MaterialID;
                wBatchRecord.MaterialNo = wItem.MaterialCode;
                wBatchRecord.MaterialName = wItem.MaterialName;

                wBatchRecord.RuleCode = wMSSBatchRange.RuleCode;
                if (wBatchRecord.ProductDate == null) {
                    wBatchRecord.ProductDate = Calendar.getInstance();
                }
                if (wBatchRecord.ExpireDate == null) {
                    wBatchRecord.ExpireDate = CalendarTool.AddCalendar(Calendar.getInstance(), Calendar.YEAR, 10);
                }
                if (wBatchRecord.StockDate == null) {
                    wBatchRecord.StockDate = Calendar.getInstance();
                }
                MSSBatchRecordDAO.getInstance().UpdatePo(wLoginUser, wBatchRecord, wErrorCode);

                if (wErrorCode.Result != 0) {
                    return;
                }
                if (wItem.BatchRecordID <= 0) {
                    wItem.BatchRecordCode = wBatchRecord.Code;
                    wItem.BatchRecordID = wBatchRecord.ID;
                }
                wBatchRecordMap.put(wWorkPieceNo, wBatchRecord);
                //创建批次信息
            }

            wItem.BatchRecordCode = wWorkPieceNo;
            wItem.BatchRecordID = wBatchRecordMap.get(wWorkPieceNo).ID;

            wOutboundOrderItemMap.put(wWorkPieceNo, StringUtils.parseListArgs(wItem));
            wWMSOutboundOrder.ItemList.add(wItem);
            wWMSOutboundOrderItemList.add(wItem);
        }

        ServiceResult<Integer> wServiceResult = WMSServiceImpl.getInstance().WMS_UpdateOutboundOrderItemList(wLoginUser, wWMSOutboundOrderItemList);

        if (StringUtils.isNotEmpty(wServiceResult.FaultCode)) {
            log.info("WMS_AutoInStock WMS_UpdateOutboundOrderItemList {}", wServiceResult.FaultCode);
        }

    }

    /**
     * 半成品出库
     * 交接扣减半成品库存
     *
     * @param wLoginUser
     * @param wTaskPartPointDay
     */
    public void WMS_AutoSemiOutStock(BMSEmployee wLoginUser, APSTaskPartPointDay wTaskPartPointDay, float wNumber, int wStationID, OutResult<Integer> wErrorCode) {
        //一个班次日计划只有一个入库单
        try {

            if (wTaskPartPointDay == null || wTaskPartPointDay.ID <= 0 || wNumber <= 0)
                return;

            OMSOrder wOMSOrder = OMSOrderDAO.getInstance().SelectPO(wLoginUser, wTaskPartPointDay.OrderID, "", wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wOMSOrder == null || wOMSOrder.ID <= 0 || wTaskPartPointDay.ProductID <= 0)
                return;

            double wNeedFQTY = wNumber;
            /**
             * 原材料类型的出库（原材料扫码数据）
             */
            FPCProductCom wFPCProductCom = FPCProductComDAO.getInstance().FPC_SelectProductCom(wLoginUser,
                    wTaskPartPointDay.ProductID, wTaskPartPointDay.ScanComponentType, wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wFPCProductCom == null || wFPCProductCom.ID <= 0 || wFPCProductCom.MaterialID <= 0) {
                log.info("产品:{0} 元件{1} 未配置物料号", wTaskPartPointDay.ProductNo, PDMComponentTypes.getEnumType(wTaskPartPointDay.ScanComponentType).getLabel());
                return;
            }

            MSSMaterial wMaterial = CacheUtils.GetCacheInfo(MSSMaterial.class, wFPCProductCom.MaterialID, "");
            if (wMaterial == null || wMaterial.ID <= 0) {
                log.info("产品:{0} 配置的物料ID{1}不存在", wTaskPartPointDay.ProductNo, wFPCProductCom.MaterialID);
                return;
            }

            //查询工位库位对应表
            List<WMSResource> wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                    -1, -1, -1, -1, StringUtils.parseListArgs(wStationID),
                    null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;
            if (wResourceList == null)
                wResourceList = new ArrayList<>();

            List<Integer> wStoreStationIDs = wResourceList.stream().map(p -> p.StoreStationID).distinct().collect(Collectors.toList());

            wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                    -1, -1, -1, -1, wTaskPartPointDay.StationID,
                    null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;
            if (wResourceList == null || wResourceList.size() == 0) {
                wErrorCode.Result = ExceptionTypes.NotFound.getValue();
                return;
            }
            List<Integer> wStoreStationIDList = wResourceList.stream().map(p -> p.StoreStationID).distinct().collect(Collectors.toList());


            //查询库位库存信息
            List<WMSStockRecord> wStockRecordList = WMSStockRecordDAO.getInstance().WMS_QueryStockRecordList(wLoginUser,
                    -1, wStoreStationIDList, wMaterial.ID, Pagination.getMaxSize(WMSStockRecord.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;

            if (wStockRecordList == null || wStockRecordList.size() == 0) {
                log.info("产品:{0} 元件{1} 物料{2} 无库存", wTaskPartPointDay.ProductNo,
                        PDMComponentTypes.getEnumType(wTaskPartPointDay.ScanComponentType).getLabel(), wMaterial.Code);
                return;
            }
            Map<String, WMSStockRecord> wStockRecordMap = wStockRecordList.stream().collect(Collectors.toMap(p -> p.Code, p -> p, (o1, o2) -> o1));


            WMSOutboundOrder wWMSOutboundOrder = WMSOutboundOrderDAO.getInstance()
                    .WMS_SelectOutboundOrderByTaskID(wLoginUser, wTaskPartPointDay.ID,
                            WMSStockRecordType.ProductionWarehousing.getValue(), wErrorCode);

            if (wWMSOutboundOrder == null || wWMSOutboundOrder.ID <= 0) {
                wWMSOutboundOrder = this.CreateOutboundOrder(wTaskPartPointDay, wOMSOrder, WMSStockRecordType.ProductionWarehousing);

                WMSOutboundOrderDAO.getInstance().UpdatePo(wLoginUser, wWMSOutboundOrder, wErrorCode);
                if (wErrorCode.Result != 0)
                    return;
            } else if (wWMSOutboundOrder.ItemList == null || wWMSOutboundOrder.ItemList.size() == 0) {
                wWMSOutboundOrder.ItemList = WMSOutboundOrderItemDAO.getInstance().WMS_SelectOutboundOrderItemList(wLoginUser,
                        wWMSOutboundOrder.ID, Pagination.getMaxSize(WMSOutboundOrderItem.class), wErrorCode);
                if (wErrorCode.Result != 0)
                    return;

                if (wWMSOutboundOrder.ItemList == null)
                    wWMSOutboundOrder.ItemList = new ArrayList<>();
            }

            Map<String, List<WMSOutboundOrderItem>> wOutboundOrderItemMap = wWMSOutboundOrder.ItemList.stream()
                    .collect(Collectors.groupingBy(p -> p.BatchRecordCode));
            if (wErrorCode.Result != 0)
                return;


            WMSOutboundOrderItem wItem;
            List<WMSOutboundOrderItem> wOutboundOrderItemList = new ArrayList<>();


            //region step 2 同工位库位 不同批次号   扣除已经扣过 且库存时间较长的

            List<WMSStockRecord> wStockRecordListTemp = wStockRecordList.stream().filter(p -> wStoreStationIDs.contains(p.StoreStationID))
                    .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

            wNeedFQTY = this.AddOutboundOrderItem(wStockRecordListTemp, wWMSOutboundOrder, wOMSOrder, wNeedFQTY, wOutboundOrderItemList);

            //endregion


            //region step 2.1 同工序库位 不同批次号   扣除已经扣过 且库存时间较长的
            if (wNeedFQTY > 0) {
                wStockRecordListTemp = wStockRecordList.stream().filter(p -> wStoreStationIDList.contains(p.StoreStationID))
                        .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

                wNeedFQTY = this.AddOutboundOrderItem(wStockRecordListTemp, wWMSOutboundOrder, wOMSOrder, wNeedFQTY, wOutboundOrderItemList);
            }
            //endregion

            //region step 3  不同工序库位 不同批次号  扣除已经扣过 且库存时间较长的
            if (wNeedFQTY > 0) {

                wStockRecordListTemp = wStockRecordList.stream().filter(p -> !wStoreStationIDList.contains(p.StoreStationID))
                        .sorted(Comparator.comparing(WMSStockRecord::getProductDate).thenComparing(o -> o.ID)).collect(Collectors.toList());

                wNeedFQTY = this.AddOutboundOrderItem(wStockRecordListTemp, wWMSOutboundOrder, wOMSOrder, wNeedFQTY, wOutboundOrderItemList);
            }
            //endregion

            if (wNeedFQTY > 0) {
                //库存最多扣减为0    但是需要备注无库存可扣减说明   暂时使用日志解决
                log.info("产品：{0} 元件{1} 半成品物料 {2} 在{3}工序出库库存不足", wOMSOrder.ProductCode,
                        PDMComponentTypes.getEnumType(wTaskPartPointDay.ScanComponentType).getLabel(), wMaterial.Code, wTaskPartPointDay.RoutePartPointName);
            }

            ServiceResult<Integer> wServiceResult = WMSServiceImpl.getInstance().WMS_UpdateOutboundOrderItemList(wLoginUser, wOutboundOrderItemList);

            if (StringUtils.isNotEmpty(wServiceResult.FaultCode)) {
                log.info("WMS_AutoSemiOutStock WMS_UpdateOutboundOrderItemList {}", wServiceResult.FaultCode);
            }
            MRPDeliveryDAO.getInstance().MRP_UpdateDeliveryFQTYUsed(wLoginUser,  wTaskPartPointDay.StationDate,
                    CalendarTool.AddCalendar( wTaskPartPointDay.StationDate,Calendar.DAY_OF_MONTH,1), wErrorCode);

        } catch (Exception e) {
            wErrorCode.Result = ExceptionTypes.Exception.getValue();
            log.error("WMS_AutoSemiOutStock", e);
        }

    }

    /**
     * 半成品入库
     * 交接下工序增加半成品库存
     *
     * @param wLoginUser
     * @param wTaskPartPointDay
     */
    public void WMS_AutoSemiInStock(BMSEmployee wLoginUser, APSTaskPartPointDay wTaskPartPointDay, float wNumber,  int wStationID,OutResult<Integer> wErrorCode) {
        //一个班次日计划只有一个入库单
        try {

            if (wTaskPartPointDay == null || wTaskPartPointDay.ID <= 0)
                return;

            OMSOrder wOMSOrder = OMSOrderDAO.getInstance().SelectPO(wLoginUser, wTaskPartPointDay.OrderID, "", wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wOMSOrder == null || wOMSOrder.ID <= 0)
                return;

            /**
             * 半成品的入库（半成品扫码数据）
             */
            FPCProductCom wFPCProductCom = FPCProductComDAO.getInstance().FPC_SelectProductCom(wLoginUser,
                    wTaskPartPointDay.ProductID, wTaskPartPointDay.ScanComponentType, wErrorCode);

            if (wErrorCode.Result != 0)
                return;
            if (wFPCProductCom == null || wFPCProductCom.ID <= 0 || wFPCProductCom.MaterialID <= 0) {
                log.info("产品:{0} 元件{1} 未配置物料号", wTaskPartPointDay.ProductNo, PDMComponentTypes.getEnumType(wTaskPartPointDay.ScanComponentType).getLabel());
                return;
            }

            MSSMaterial wMaterial = CacheUtils.GetCacheInfo(MSSMaterial.class, wFPCProductCom.MaterialID, "");
            if (wMaterial == null || wMaterial.ID <= 0) {
                log.info("产品:{0} 配置的物料ID{1}不存在", wTaskPartPointDay.ProductNo, wFPCProductCom.MaterialID);
                return;
            }



            MSSBatchRange wMSSBatchRange = MSSBatchRangeDAO.getInstance().MSS_QueryBatchRange(wLoginUser, wOMSOrder.CustomerID, wMaterial.Code, wErrorCode);

            if (wErrorCode.Result != 0)
                return;


            //查询工位库位对应表
            List<WMSResource> wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                    -1, -1, -1, -1, StringUtils.parseListArgs(wStationID),
                    null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
            if (wErrorCode.Result != 0)
                return;
            if (wResourceList == null || wResourceList.size() == 0) {
                wResourceList = WMSResourceDAO.getInstance().WMS_QueryResourceList(wLoginUser, -1,
                        -1, -1, -1, -1, wTaskPartPointDay.StationID,
                        null, Pagination.getMaxSize(WMSResource.class), wErrorCode);
                if (wErrorCode.Result != 0)
                    return;
                if (wResourceList == null || wResourceList.size() == 0) {
                    wErrorCode.Result = ExceptionTypes.NotFound.getValue();
                    return;
                }
            }
            List<Integer> wStoreStationIDList = wResourceList.stream().map(p -> p.StoreStationID).distinct().collect(Collectors.toList());

            List<WMSStoreStation> wStoreStationList = WMSStoreStationDAO.getInstance().SelectPOList(wLoginUser, wStoreStationIDList,
                    Pagination.getMaxSize(WMSStoreStation.class), wErrorCode);

            if (wErrorCode.Result != 0)
                return;

            if (wStoreStationList == null || wStoreStationList.size() == 0) {
                wErrorCode.Result = ExceptionTypes.NotFound.getValue();
                return;
            }

            WMSOutboundOrder wWMSOutboundOrder = WMSOutboundOrderDAO.getInstance()
                    .WMS_SelectOutboundOrderByTaskID(wLoginUser, wTaskPartPointDay.ID,
                            WMSStockRecordType.ProductionWarehousing.getValue(), wErrorCode);

            if (wWMSOutboundOrder == null || wWMSOutboundOrder.ID <= 0) {
                wWMSOutboundOrder = this.CreateOutboundOrder(wTaskPartPointDay, wOMSOrder, WMSStockRecordType.ProductionWarehousing);

                WMSOutboundOrderDAO.getInstance().UpdatePo(wLoginUser, wWMSOutboundOrder, wErrorCode);
                if (wErrorCode.Result != 0)
                    return;
            } else if (wWMSOutboundOrder.ItemList == null || wWMSOutboundOrder.ItemList.size() == 0) {
                wWMSOutboundOrder.ItemList = WMSOutboundOrderItemDAO.getInstance().WMS_SelectOutboundOrderItemList(wLoginUser,
                        wWMSOutboundOrder.ID, Pagination.getMaxSize(WMSOutboundOrderItem.class), wErrorCode);
                if (wErrorCode.Result != 0)
                    return;

                if (wWMSOutboundOrder.ItemList == null)
                    wWMSOutboundOrder.ItemList = new ArrayList<>();
            }

            Map<String, List<WMSOutboundOrderItem>> wOutboundOrderItemMap = wWMSOutboundOrder.ItemList.stream()
                    .collect(Collectors.groupingBy(p -> p.BatchRecordCode));



            WMSOutboundOrderItem   wItem = this.CreateOutboundOrderItem(wWMSOutboundOrder, wOMSOrder, wStoreStationList.get(0), wMaterial);


            MSSBatchRecord wBatchRecord = new MSSBatchRecord();
            wBatchRecord.ID = wItem.BatchRecordID;
            wBatchRecord.Code = "";
            wBatchRecord.ExpireDate = CalendarTool.AddCalendar(wBatchRecord.ExpireDate, Calendar.YEAR, 1);
            wBatchRecord.FactoryID = wItem.FactoryID;
            wBatchRecord.FactoryCode = wItem.FactoryCode;
            wBatchRecord.FactoryName = wItem.FactoryName;
            wBatchRecord.CustomerID = wItem.SupplierID;
            wBatchRecord.CustomerCode = wItem.SupplierCode;
            wBatchRecord.CustomerName = wItem.SupplierName;

            wBatchRecord.MaterialID = wItem.MaterialID;
            wBatchRecord.MaterialNo = wItem.MaterialCode;
            wBatchRecord.MaterialName = wItem.MaterialName;

            wBatchRecord.RuleCode = wMSSBatchRange.RuleCode;
            if (wBatchRecord.ProductDate == null) {
                wBatchRecord.ProductDate = Calendar.getInstance();
            }
            if (wBatchRecord.ExpireDate == null) {
                wBatchRecord.ExpireDate = CalendarTool.AddCalendar(Calendar.getInstance(), Calendar.YEAR, 10);
            }
            if (wBatchRecord.StockDate == null) {
                wBatchRecord.StockDate = Calendar.getInstance();
            }
            MSSBatchRecordDAO.getInstance().UpdatePo(wLoginUser, wBatchRecord, wErrorCode);

            if (wErrorCode.Result != 0) {
                return;
            }
            if (wItem.BatchRecordID <= 0) {
                wItem.BatchRecordID = wBatchRecord.ID;
                wItem.BatchRecordCode = wBatchRecord.Code;
            }

            ServiceResult<Integer> wServiceResult = WMSServiceImpl.getInstance().WMS_UpdateOutboundOrderItem(wLoginUser, wItem);

            if (StringUtils.isNotEmpty(wServiceResult.FaultCode)) {
                log.info("WMS_AutoSemiInStock WMS_UpdateOutboundOrderItem {}", wServiceResult.FaultCode);
            }

        } catch (Exception e) {
            wErrorCode.Result = ExceptionTypes.Exception.getValue();
            log.error("WMS_AutoSemiInStock", e);
        }

    }


}
